use core::slice;

// unsafe rust, 不安全的rust
// unsafe rust 可以做四个动作:
// 1. 解引用原始指针
// 2. 调用unsafe的函数或者方法
// 3. 访问或者修改可变的静态变量
// 4. 实现unsafe trait
fn main() {
    // 原始指针, 或裸指针
    // 可变的原始指针: *mut T;
    // 不可变的原始指针: *const T;
    // 注意这里的*不是解引用, 而是类型名的一部分;
    // 与引用不同, 原始指针:
    // 1. 可以是多个可变指针指向同一位置, 或可变/不可变混合指向一个位置
    // 2. 原始指针无法保证指向合理的内存;
    // 3. 允许为null;
    // 4. 原始指针不实现任何的自动清理;
    // 放弃了这些安全保障, 换回了更好的性能和与其他语言或者接口的能力
    
    
    // 1. 创建原始指针
    // 我们可以不在unsafe块外创建原始指针, 但是, 只能在unsafe 块内对其解引用
    let mut num = 5;
    // 分别将可变和不可变引用转为了原始指针
    let r1 = &num as *const i32;
    let r2 = &mut num as *mut i32;

    // 我们不能直接在外面对以上原始指针进行解引用
    // println!("r1: {}", *r1);
    // println!("r2: {}", *r2);

    // 需要将其放入unsafe块中
    unsafe {
        println!("r1: {}", *r1);
        println!("r2: {}", *r2);
    }


    // 以上代码至少能够确定其有效性, 还有无法确定有效性的代码
    // 以下操作非常危险, 因为有可能访问的是一个无效地址
    let address = 0x012346usize;
    let _r = address as *const i32;

    // 以下注释掉, 因为报错会阻塞后续代码;
    // unsafe {
    //     println!("r: {}", *_r);
    //     // 执行后结果只有: Segmentation fault: 11; 即访问了无效地址
    // }
    // 之所以要使用原始指针: 1. 与c语言接口; 2. 构建借用检查器无法理解的安全抽象;

    // 2. 调用unsafe 函数或者方法, 所谓的unsafe函数或方法就是在定义前加上了unsafe关键字的函数/方法
    // unsafe 函数或者方法需要在unsafe 块中调用; unsafe 函数或者方法也属于unsafe块
    unsafe fn dangerous() {
        println!("this is dangerous")
    }

    // 只能在unsafe块中进行调用;
    unsafe {
        dangerous();
    }
    // 3. 创建unsafe代码的安全抽象
    let mut v = vec![1,2,3,4,5,6];
    // 利用v[..]表示创造了一个切片, 其包含了向量v中的所有元素
    // &mut v[..]表示创建了一个可变切片到这个引用
    let p = &mut v[..];
    let (a, b) = p.split_at_mut(3);
    assert_eq!(a, &mut [1,2,3]);
    assert_eq!(b, &mut [4,5,6]);
    println!("ok"); // 如果以上断言没错, 则会执行到此处
    // 上面的split_at_mut其实就用了unsafe代码, 此处做一个还原:
    // fn split_at_mut(slice: &mut [i32], mid: usize) -> (&mut [i32], &mut [i32]) {
    //     let len = slice.len();
    //     assert!(mid <= len);
    //     // 此处就报错了, 因为我们对slice切片进行了两次可变借用, 这是不被允许的
    //     // 但是, 实际上又是可以执行的, 毕竟这切开的两部分并无任何交集, 但rust并不理解这个
    //     // 所以, 就要用到不安全代码了
    //     (&mut slice[..mid], &mut slice[mid..])
    // }
    // 改为不安全版本
    fn split_at_mut(slice: &mut [i32], mid: usize) -> (&mut [i32], &mut [i32]) {
        let len = slice.len();
        // 返回一个指向切片第一个元素的原始、未加工的可变指针（raw mutable pointer）
        let ptr = slice.as_mut_ptr();
        assert!(mid <= len);
        unsafe {
            (
                slice::from_raw_parts_mut(ptr, mid),
                slice::from_raw_parts_mut(ptr.add(mid), len - mid)
            )
        }
    }
    let (part1, part2) = split_at_mut(p, 3);
    assert_eq!(part1, &mut [1,2,3]);
    assert_eq!(part2, &mut [4,5,6]);
    println!("ok2");
    // 4. 使用extern函数来调用外部代码
    // 这里定义的c语言, rust无法对其进行检查, 所以, 需要在后续的unsafe块中调用
    // extern 关键字通常用于声明外部函数接口（Foreign Function Interface, FFI），它允许Rust代码调用其他编程语言（如C或C++）编写的函数
    extern "C" {
        fn abs(input: i32) -> i32;
    }
    unsafe {
        println!("C result: {}", abs(12));
    }

    // 6. 静态变量
    // 访问不可变静态变量, 安全
    println!("HELLO_WORLD: {}", HELLO_WORLD);
    // 修改可变静态变量不安全, 需要用到unsafe块;
    // 因为如果是多线程的情况下, 很难保证不发生数据竞争
    // 此时就要用到之前的智能指针(todo)
    add_to_count(12);

    // 7.实现不安全trait; 当某个trait至少存在一个方法拥有编译器无法校验的不安全因素, 则该trait是为不安全trait
    // 该trait只能在unsafe代码块中实现
    unsafe trait Foo {

    }
    unsafe impl Foo for i32 {}
   
}

 // 5. 从其他语言调用rust函数
 #[no_mangle] // 编译后, 不要修改函数名
 pub extern "C" fn call_from_c () {
    println!("Just call from C!")
 }
//  从c语言可以调用此函数

// 6. 访问或修改一个可变的静态变量, rust支持全局变量, 但由于所有权机制可能产生数据竞争等问题
// 全局变量又叫静态变量(static)
// 特点: 1. 必须标注类型; 2. 只能存储'static 生命周期的引用, 无需显示标注; 3. 访问不可变的静态变量是安全的
// 4. 但访问和修改可变的静态变量是不安全的

static mut COUNTER:i32 = 0;
fn add_to_count(inc: i32) {
    unsafe {
        COUNTER += inc;
    }
}
static HELLO_WORLD:&str = "hello world";

